<template>
	<div class="chat-input-area">
		<div :class="['edit-chat-container', isEmpty ? '' : 'not-empty']" contenteditable="true"
			@paste.prevent="onPaste" @keydown="onKeydown" @compositionstart="compositionFlag = true"
			@compositionend="onCompositionEnd" @input="onEditorInput" @mousedown="onMousedown" ref="content"
			@blur="onBlur">
		</div>
		<chat-at-box @select="onAtSelect" :search-text="atSearchText" ref="atBox" :ownerId="ownerId"
			:members="groupMembers"></chat-at-box>
		<!-- 图片预览组件 -->
		<full-image ref="fullImage"></full-image>
	</div>
</template>

<script>
import ChatAtBox from "./ChatAtBox.vue";
import FullImage from "../common/FullImage.vue";

export default {
	name: "ChatInput",
	components: { ChatAtBox, FullImage },
	props: {
		ownerId: {
			type: Number,
		},
		groupMembers: {
			type: Array,
		},
	},
	data() {
		return {
			imageList: [],
			fileList: [],
			currentId: 0,
			atSearchText: null,
			compositionFlag: false,
			atIng: false,
			isEmpty: true,
			changeStored: true,
			blurRange: null,
			lastSubmitTime: 0 // 上次提交时间，用于防抖
		}
	},
	methods: {
		onPaste(e) {
			this.isEmpty = false;
			let txt = e.clipboardData.getData('Text')
			let range = window.getSelection().getRangeAt(0)
			if (range.startContainer !== range.endContainer || range.startOffset !== range.endOffset) {
				range.deleteContents();
			}
			// 粘贴图片和文件时，这里没有数据
			if (txt && typeof (txt) == 'string') {
				let textNode = document.createTextNode(txt);
				range.insertNode(textNode)
				range.collapse();
				return;
			}
			let items = (e.clipboardData || window.clipboardData).items
			if (items.length) {
				for (let i = 0; i < items.length; i++) {
					if (items[i].type.indexOf('image') !== -1) {
						let file = items[i].getAsFile();
						// 生成唯一的图片名称
						const extension = this.getExtensionFromMimeType(file.type);
						const uniqueName = this.generateUniqueImageName(file.name, extension);

						let imagePush = {
							fileId: this.generateId(),
							file: file,
							url: URL.createObjectURL(file),
							uniqueName: uniqueName // 保存唯一名称
						};
						this.imageList[imagePush.fileId] = (imagePush);
						let line = this.newLine();
						let imageElement = document.createElement('img');
						imageElement.className = 'chat-image no-text';
						imageElement.src = imagePush.url;
						imageElement.dataset.imgId = imagePush.fileId;
						imageElement.title = '点击预览图片';
						imageElement.style.cursor = 'pointer';
						// 添加点击事件来预览图片
						imageElement.addEventListener('click', (e) => {
							e.preventDefault();
							e.stopPropagation();
							this.previewImage(imagePush.url, uniqueName);
						});
						line.appendChild(imageElement);
						let after = document.createTextNode('\u00A0');
						line.appendChild(after);
						this.selectElement(after, 1);
					} else {
						let asFile = items[i].getAsFile();
						if (!asFile) {
							continue;
						}
						let filePush = { fileId: this.generateId(), file: asFile };
						this.fileList[filePush.fileId] = (filePush)
						let line = this.newLine();
						let fileElement = this.createFile(filePush);
						line.appendChild(fileElement);
						let after = document.createTextNode('\u00A0');
						line.appendChild(after);
						this.selectElement(after, 1);
					}
				}
			}
			range.collapse();
		},
		selectElement(element, endOffset) {
			let selection = window.getSelection();
			// 插入元素可能不是立即执行的，vue可能会在插入元素后再更新dom
			this.$nextTick(() => {
				let t1 = document.createRange();
				t1.setStart(element, 0);
				t1.setEnd(element, endOffset || 0);
				if (element.firstChild) {
					t1.selectNodeContents(element.firstChild);
				}
				t1.collapse();
				selection.removeAllRanges();
				selection.addRange(t1);
				// 需要时自动聚焦，防止页面滚动
				if (element.focus) {
					element.focus({ preventScroll: true });
				}
			})
		},
		onCompositionEnd(e) {
			this.compositionFlag = false;
			this.onEditorInput(e);
		},
		onKeydown(e) {
			if (e.keyCode === 13) {
				e.preventDefault();
				e.stopPropagation();
				if (this.atIng) {
					this.$refs.atBox.select();
					return;
				}
				if (e.ctrlKey) {
					let line = this.newLine();
					let after = document.createTextNode('\u00A0');
					line.appendChild(after);
					this.selectElement(line.childNodes[0], 0);
				} else {
					// 中文输入标记
					if (this.compositionFlag) {
						return;
					}
					this.submit();
				}
				return;
			}
			// 删除键
			if (e.keyCode === 8) {
				// 等待dom更新
				setTimeout(() => {
					let s = this.$refs.content.innerHTML.trim();
					// 空dom时，需要刷新dom
					if (s === '' || s === '<br>' || s === '<div>&nbsp;</div>') {
						// 拼接随机长度的空格，以刷新dom
						this.empty();
						this.isEmpty = true;
						this.selectElement(this.$refs.content);
					} else {
						this.isEmpty = false;
					}
				})
			}
			// at框打开时，上下键移动特殊处理
			if (this.atIng) {
				if (e.keyCode === 38) {
					e.preventDefault();
					e.stopPropagation();
					this.$refs.atBox.moveUp();
				}
				if (e.keyCode === 40) {
					e.preventDefault();
					e.stopPropagation();
					this.$refs.atBox.moveDown();
				}
			}

		},
		onAtSelect(member) {
			this.atIng = false;
			// 选中输入的 @xx 符
			let blurRange = this.blurRange;
			let endContainer = blurRange.endContainer
			let startOffset = endContainer.data.indexOf("@" + this.atSearchText);
			let endOffset = startOffset + this.atSearchText.length + 1;
			blurRange.setStart(blurRange.endContainer, startOffset);
			blurRange.setEnd(blurRange.endContainer, endOffset);
			blurRange.deleteContents()
			blurRange.collapse();
			this.focus();
			// 创建元素节点
			let element = document.createElement('SPAN')
			element.className = "chat-at-user";
			element.dataset.id = member.userId;
			element.contentEditable = 'false'
			element.innerText = `@${member.showNickName}`
			blurRange.insertNode(element)
			// 光标移动到末尾
			blurRange.collapse()

			// 插入空格
			let textNode = document.createTextNode('\u00A0');
			blurRange.insertNode(textNode);

			blurRange.collapse()
			this.atSearchText = "";
			this.selectElement(textNode, 1);
		},
		onEditorInput(e) {
			this.isEmpty = false;
			this.changeStored = false;
			if (this.$props.groupMembers && !this.compositionFlag) {
				let selection = window.getSelection()
				let range = selection.getRangeAt(0);
				// 截取@后面的名称作为过滤条件，并以空格结束
				let endContainer = range.endContainer;
				let endOffset = range.endOffset;
				let textContent = endContainer.textContent;
				let startIndex = -1;
				for (let i = endOffset; i >= 0; i--) {
					if (textContent[i] === '@') {
						startIndex = i;
						break;
					}
				}
				// 没有at符号，则关闭弹窗
				if (startIndex === -1) {
					this.$refs.atBox.close();
					return;
				}

				let endIndex = endOffset;
				for (let i = endOffset; i < textContent.length; i++) {
					if (textContent[i] === ' ') {
						endIndex = i;
						break;
					}
				}
				this.atSearchText = textContent.substring(startIndex + 1, endIndex).trim();
				// 打开选择弹窗
				if (this.atSearchText == '') {
					this.showAtBox(e)
				}
			}

		},
		onBlur(e) {
			if (!this.atIng) {
				this.updateRange();
			}
		},
		onMousedown(e) {
			// 如果点击的是图片，触发预览
			if (e.target.tagName === 'IMG' && e.target.classList.contains('chat-image')) {
				e.preventDefault();
				e.stopPropagation();
				const imgId = e.target.dataset.imgId;
				if (imgId && this.imageList[imgId]) {
					const imageData = this.imageList[imgId];
					// 使用唯一名称或生成的名称
					const imageName = imageData.uniqueName || imageData.file?.name || '输入框图片';
					this.previewImage(imageData.url, imageName);
				}
				return;
			}

			if (this.atIng) {
				this.$refs.atBox.close();
				this.atIng = false;
			}
		},
		insertEmoji(emojiText) {
			let emojiElement = document.createElement('img');
			emojiElement.className = 'emoji-normal no-text';
			emojiElement.dataset.emojiCode = emojiText;
			emojiElement.src = this.$emo.textToUrl(emojiText);

			let blurRange = this.blurRange;
			if (!blurRange) {
				this.focus();
				this.updateRange();
				blurRange = this.blurRange;
			}
			if (blurRange.startContainer !== blurRange.endContainer || blurRange.startOffset !== blurRange.endOffset) {
				blurRange.deleteContents();
			}
			blurRange.insertNode(emojiElement);
			blurRange.collapse()

			let textNode = document.createTextNode('\u00A0');
			blurRange.insertNode(textNode)
			blurRange.collapse()

			this.selectElement(textNode);
			this.updateRange();
			this.isEmpty = false;
		},
		generateId() {
			return this.currentId++;
		},

		/**
		 * 生成唯一的图片文件名
		 * @param {string} originalName - 原始文件名
		 * @param {string} extension - 文件扩展名
		 * @returns {string} 唯一的文件名
		 */
		generateUniqueImageName(originalName = '', extension = 'jpg') {
			// 获取当前时间戳（取后6位）
			const timestamp = Date.now().toString().slice(-6);
			// 生成随机数（3位）
			const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
			// 格式化当前时间（简化版）
			const now = new Date();
			const timeStr = now.getHours().toString().padStart(2, '0') +
				now.getMinutes().toString().padStart(2, '0');

			// 如果有原始文件名，提取其扩展名
			if (originalName && originalName.includes('.')) {
				const parts = originalName.split('.');
				extension = parts[parts.length - 1].toLowerCase();
			}

			// 生成格式：img_HHMM_timestamp_random.ext (更简洁)
			return `img_${timeStr}_${timestamp}_${random}.${extension}`;
		},

		/**
		 * 从文件类型获取扩展名
		 * @param {string} mimeType - MIME类型
		 * @returns {string} 文件扩展名
		 */
		getExtensionFromMimeType(mimeType) {
			const mimeToExt = {
				'image/jpeg': 'jpg',
				'image/jpg': 'jpg',
				'image/png': 'png',
				'image/gif': 'gif',
				'image/webp': 'webp',
				'image/bmp': 'bmp',
				'image/svg+xml': 'svg'
			};
			return mimeToExt[mimeType] || 'jpg';
		},
		createFile(filePush) {
			let file = filePush.file;
			let fileId = filePush.fileId;
			let container = document.createElement('div');
			container.className = 'chat-file-container no-text';
			container.contentEditable = 'false';
			container.dataset.fileId = fileId;

			let left = document.createElement('div');
			left.className = 'file-position-left';
			container.appendChild(left);

			let icon = document.createElement('div');
			icon.className = 'el-icon-document';
			left.appendChild(icon);

			let right = document.createElement('div');
			right.className = 'file-position-right';
			container.appendChild(right);

			let fileName = document.createElement('div');
			fileName.className = 'file-name';
			fileName.innerText = file.name;

			let fileSize = document.createElement('div');
			fileSize.className = 'file-size';
			fileSize.innerText = this.sizeConvert(file.size);

			right.appendChild(fileName);
			right.appendChild(fileSize);

			return container;
		},
		sizeConvert(len) {
			if (len < 1024) {
				return len + 'B';
			} else if (len < 1024 * 1024) {
				return (len / 1024).toFixed(2) + 'KB';
			} else if (len < 1024 * 1024 * 1024) {
				return (len / 1024 / 1024).toFixed(2) + 'MB';
			} else {
				return (len / 1024 / 1024 / 1024).toFixed(2) + 'GB';
			}
		},
		updateRange() {
			let selection = window.getSelection();
			this.blurRange = selection.getRangeAt(0);
		},
		newLine() {
			let selection = window.getSelection();
			let range = selection.getRangeAt(0);
			let divElement = document.createElement('div');
			let endContainer = range.endContainer;
			let parentElement = endContainer.parentElement;
			if (parentElement.parentElement === this.$refs.content) {
				divElement.innerHTML = endContainer.textContent.substring(range.endOffset).trim();
				endContainer.textContent = endContainer.textContent.substring(0, range.endOffset);
				// 插入到当前div（当前行）后面
				parentElement.insertAdjacentElement('afterend', divElement);
			} else {
				divElement.innerHTML = '';
				this.$refs.content.append(divElement);
			}
			return divElement;
		},
		clear() {
			this.empty();
			this.imageList = [];
			this.fileList = [];
			this.$refs.atBox.close();
		},
		empty() {
			this.$refs.content.innerHTML = "";
			let line = this.newLine();
			let after = document.createTextNode('\u00A0');
			line.appendChild(after);
			this.$nextTick(() => this.selectElement(after));
		},
		showAtBox(e) {
			this.atIng = true;
			// show之后会自动更新当前搜索的text
			// this.atSearchText = "";
			let selection = window.getSelection()
			let range = selection.getRangeAt(0)
			// 光标所在坐标
			let pos = range.getBoundingClientRect();
			this.$refs.atBox.open({
				x: pos.x,
				y: pos.y
			})
			// 记录光标所在位置
			this.updateRange();
		},
		html2Escape(strHtml) {
			return strHtml.replace(/[<>&"]/g, function (c) {
				return {
					'<': '&lt;',
					'>': '&gt;',
					'&': '&amp;',
					'"': '&quot;'
				}[c];
			});
		},
		submit() {
			// 防抖处理：防止短时间内重复提交
			const now = Date.now();
			if (this.lastSubmitTime && (now - this.lastSubmitTime) < 500) {
				console.warn('提交过于频繁，忽略重复提交');
				return;
			}
			this.lastSubmitTime = now;

			let nodes = this.$refs.content.childNodes;
			let fullList = [];
			let tempText = '';
			let atUserIds = [];
			let each = (nodes) => {
				for (let i = 0; i < nodes.length; i++) {
					let node = nodes[i];
					if (!node) {
						continue;
					}
					if (node.nodeType === 3) {
						tempText += this.html2Escape(node.textContent);
						continue;
					}
					let nodeName = node.nodeName.toLowerCase();
					if (nodeName === 'script') {
						continue;
					}
					let text = tempText.trim();
					if (nodeName === 'img') {
						let imgId = node.dataset.imgId;
						if (imgId) {
							if (text) {
								fullList.push({
									type: 'text',
									content: text,
									atUserIds: atUserIds
								})
								tempText = '';
								atUserIds = []
							}
							fullList.push({
								type: 'image',
								content: this.imageList[imgId]
							})
						} else {
							let emojiCode = node.dataset.emojiCode;
							tempText += emojiCode;
						}
					} else if (nodeName === 'div') {
						let fileId = node.dataset.fileId
						// 文件
						if (fileId) {
							if (text) {
								fullList.push({
									type: 'text',
									content: text,
									atUserIds: atUserIds
								})
								tempText = '';
								atUserIds = []
							}
							fullList.push({
								type: 'file',
								content: this.fileList[fileId]
							})
						} else {
							tempText += '\n';
							each(node.childNodes);
						}
					} else if (nodeName === 'span') {
						if (node.dataset.id) {
							tempText += node.innerHTML;
							atUserIds.push(node.dataset.id)
						} else if (node.outerHtml) {
							tempText += node.outerHtml;
						}
					}
				}
			}
			each(nodes)
			let text = tempText.trim();
			if (text !== '') {
				fullList.push({
					type: 'text',
					content: text,
					atUserIds: atUserIds
				})
			}
			this.$emit('submit', fullList);
		},
		focus() {
			// 防止聚焦时导致页面滚动
			const element = this.$refs.content;
			if (element) {
				// 使用 preventScroll 选项防止自动滚动
				element.focus({ preventScroll: true });
			}
		},

		/**
		 * 预览图片
		 * @param {string} imageUrl - 图片URL
		 * @param {string} imageName - 图片名称
		 */
		previewImage(imageUrl, imageName = '') {
			if (this.$refs.fullImage) {
				this.$refs.fullImage.open({
					url: imageUrl,
					name: imageName
				});
			}
		}

	}
}
</script>

<style lang="scss">
@use "@/styles/variables.scss" as *;

.chat-input-area {
	width: 100%;
	height: 100%;
	position: relative;
	min-height: 120px;

	.edit-chat-container {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		outline: none;
		padding: var(--im-spacing-lg);
		line-height: 1.5;
		font-size: var(--im-font-size-base);
		font-family: var(--im-font-family);
		color: var(--im-text-color-primary);
		text-align: left;
		overflow-y: auto;
		overflow-x: hidden;
		background: var(--im-bg-primary);
		border: var(--im-border-light);
		border-radius: var(--im-border-radius-lg);
		transition: all var(--im-transition-base);

		&:focus {
			border-color: var(--im-color-primary);
			box-shadow: 0 0 0 2px var(--im-color-primary-light-8);
		}

		&:hover:not(:focus) {
			border-color: var(--im-color-primary-light-4);
		}

		// 单独一行时，无法在前面输入的bug
		>div:before {
			content: "\00a0";
			font-size: var(--im-font-size-base);
			position: absolute;
			top: 0;
			left: 0;
			opacity: 0;
		}

		// 聊天图片样式
		.chat-image {
			display: block;
			max-width: 200px;
			max-height: 120px;
			border: var(--im-border-light);
			border-radius: var(--im-border-radius-base);
			cursor: pointer;
			transition: all var(--im-transition-base);
			object-fit: cover;
			position: relative;

			&:hover {
				border-color: var(--im-color-primary);
				transform: scale(1.02);
				box-shadow: var(--im-box-shadow-base);
			}

			// 添加预览提示
			&::after {
				content: '点击预览';
				position: absolute;
				top: 50%;
				left: 50%;
				transform: translate(-50%, -50%);
				background: rgba(0, 0, 0, 0.7);
				color: white;
				padding: 4px 8px;
				border-radius: 4px;
				font-size: 12px;
				opacity: 0;
				transition: opacity var(--im-transition-base);
				pointer-events: none;
				white-space: nowrap;
				z-index: 10;
			}

			&:hover::after {
				opacity: 1;
			}
		}

		// 聊天文件样式
		.chat-file-container {
			max-width: 70%;
			padding: var(--im-spacing-base);
			border: 2px solid var(--im-color-primary-light-4);
			display: flex;
			background: var(--im-bg-secondary);
			border-radius: var(--im-border-radius-lg);
			transition: all var(--im-transition-base);
			cursor: pointer;

			&:hover {
				border-color: var(--im-color-primary);
				background: var(--im-bg-hover);
				transform: translateY(-1px);
				box-shadow: var(--im-box-shadow-base);
			}

			.file-position-left {
				display: flex;
				width: 60px;
				justify-content: center;
				align-items: center;

				.el-icon-document {
					font-size: 32px;
					color: var(--im-color-primary);
				}
			}

			.file-position-right {
				flex: 1;
				padding-left: var(--im-spacing-base);

				.file-name {
					font-size: var(--im-font-size-base);
					font-weight: 500;
					color: var(--im-text-color-primary);
					margin-bottom: var(--im-spacing-xs);
					word-break: break-all;
				}

				.file-size {
					font-size: var(--im-font-size-sm);
					color: var(--im-text-color-secondary);
				}
			}
		}

		// @用户样式
		.chat-at-user {
			color: var(--im-color-primary);
			background: var(--im-color-primary-light-8);
			padding: 2px 4px;
			border-radius: var(--im-border-radius-xs);
			font-weight: 500;
		}
	}

	// 输入提示文字
	.edit-chat-container>div:nth-of-type(1):after {
		content: '请输入消息（按Ctrl+Enter键换行）';
		color: var(--im-text-color-placeholder);
		font-size: var(--im-font-size-sm);
		pointer-events: none;
	}

	.edit-chat-container.not-empty>div:nth-of-type(1):after {
		content: none;
	}
}

// === 深色模式适配 ===
:root[data-theme='dark'] {
	.chat-input-area {
		.edit-chat-container {
			background: var(--im-bg-tertiary);
			border-color: var(--im-border-color);
			color: var(--im-text-color-primary);

			&:focus {
				border-color: var(--im-color-primary);
				box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
			}
		}

		.chat-file-container {
			background: var(--im-bg-hover);
			border-color: var(--im-color-primary-light-4);

			&:hover {
				background: var(--im-bg-secondary);
			}

			.file-position-right {
				.file-name {
					color: var(--im-text-color-primary);
				}
			}
		}
	}
}
</style>